#include "cmd_session.h"

#include <stdint.h>

#include <iostream>
#include <string>

#include <boost/array.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/asio.hpp>
#include <boost/asio/buffer.hpp>
using namespace boost;
using namespace boost::asio;

#include "common/base/cmd_module.h"
#include "common/base/cmd_module_mgr.h"
#include "common/base/server_mgr.h"
#include "log/log.h"
#include "net/cmd_session.h"
#include "net/session_mgr.h"

CmdSession::CmdSession(boost::asio::io_service& ios,
                       const std::shared_ptr<SessionMgr>& sessionMgr,
                       const std::shared_ptr<ServerNetInfo>& netInfo,
                       SessionCreateType createType)
    : Session(ios, sessionMgr, netInfo, createType)
{
}


std::shared_ptr<CmdSession> CmdSession::getSharedPtr()
{
    return std::dynamic_pointer_cast<CmdSession>(shared_from_this());
}

void CmdSession::startRead()
{
    if (!getSocket().is_open())
    {
        LOG_ERROR("Socket not open.");
        return;
    }
    getSocket().async_read_some(bufs_.prepare(1024),
                                std::bind(&CmdSession::handleRead,
                                          getSharedPtr(),
                                          std::placeholders::_1, std::placeholders::_2));
}

void CmdSession::handleRead(const boost::system::error_code& e,
                            std::size_t bytes_transferred)
{
    std::string err;

    if (e && e != boost::asio::error::operation_aborted)
    {
        auto sessionMgr = sessionMgr_.lock();
        if (sessionMgr)
        {
            sessionMgr->removeSession(shared_from_this());
        }
        LOG_ERROR(e.message() << "\n" << err);
        return;
    }

    auto sessionMgr = ServerMgr::get().getMgr<SessionMgr>(ManagerType::eSession);
    if (!sessionMgr)
    {
        LOG_ERROR("Session manager not inited.");
        startRead();
        return;
    }
    auto session = sessionMgr->getListenSession(netInfo_->serverType,
                                                netInfo_->sessionType,
                                                netInfo_->serverID);
    if (!session)
    {
        LOG_ERROR("Session not found, server type:" << netInfo_->serverType
                  << " server id: " << netInfo_->serverID);
        startRead();
        return;
    }

    bufs_.commit(bytes_transferred);
    std::string cmd = buffer_cast<const char*>(bufs_.data());
    bufs_.consume(bytes_transferred);
    cmd = cmd.substr(0, cmd.find_first_of("\r\n"));

    if (!ICmdModule::doDispatch(session, cmd))
    {
        LOG_WARN("Command execute failed, cmd:" << cmd  );
        startRead();
        return;
    }
    LOG_DEBUG("Command execute suc, cmd: " << cmd  );
    startRead();
}
